package com.cloud.pole.recharge.util;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.util.Base64Utils;

/**
 * RSA加密工具类
 * 
 * Copyright: Copyright (c) 2011 Asiainfo
 * 
 * @ClassName: TransferSoapReqHelper.java
 * @Description: 该类的功能描述
 *
 * @version: v1.0.0
 * @author: zhangmeng3
 * @date: 2014-9-17 上午10:38:45
 *
 */
public class RSAUtils {  
	
    /** 
     * 加密算法RSA 
     */  
    public static final String KEY_ALGORITHM = "RSA";  
      
    /** 
     * 签名算法 
     */  
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";  
  
    /** 
     * 获取公钥的key 
     */  
    private static final String PUBLIC_KEY = "RSAPublicKey";  
      
    /** 
     * 获取私钥的key 
     */  
    private static final String PRIVATE_KEY = "RSAPrivateKey";  
      
    /**
     * RSA最大加密明文大小
     */  
    private static final int MAX_ENCRYPT_BLOCK = 64;  
    
    /** 
     * RSA最大解密密文大小 
     */  
    private static final int MAX_DECRYPT_BLOCK = 75;
    
    /**
     * RSA密钥长度
     */
    private static final int INITIAL_KEY_SIZE = 600;
  
    /**
     * <p> 
     * 生成密钥对(公钥和私钥) 
     * </p> 
     *  
     * @return 
     * @throws Exception 
     */  
    public static Map<String, Object> genKeyPair() throws Exception {  
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());
        keyPairGen.initialize(INITIAL_KEY_SIZE);
        KeyPair keyPair = keyPairGen.generateKeyPair();  
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();  
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);  
        keyMap.put(PRIVATE_KEY, privateKey);  
        return keyMap;
    }
      
    /**
     * <p> 
     * 用私钥对信息生成数字签名 
     * </p> 
     *  
     * @param data 已加密数据 
     * @param privateKey 私钥(BASE64编码) 
     *  
     * @return 
     * @throws Exception 
     */  
    public static String sign(byte[] data, String privateKey) throws Exception {  
        byte[] keyBytes = Base64Utils.decodeFromString(privateKey);  
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);  
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
        signature.initSign(privateK);
        signature.update(data);
        return Base64Utils.encodeToString(signature.sign());  
    }  
  
    /**  
     * <p> 
     * 校验数字签名 
     * </p> 
     *  
     * @param data 已加密数据 
     * @param publicKey 公钥(BASE64编码) 
     * @param sign 数字签名 
     *  
     * @return 
     * @throws Exception 
     *  
     */  
    public static boolean verify(byte[] data, String publicKey, String sign)  
            throws Exception {  
        byte[] keyBytes = Base64Utils.decodeFromString(publicKey);  
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);  
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);  
        PublicKey publicK = keyFactory.generatePublic(keySpec);  
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);  
        signature.initVerify(publicK);
        signature.update(data);  
        return signature.verify(Base64Utils.decodeFromString(sign));  
    }  
  
    /**
     * <P> 
     * 私钥解密 
     * </p> 
     *  
     * @param encryptedData 已加密数据 
     * @param privateKey 私钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */  
    public static String decryptByPrivateKey(String encrypted, String privateKey)  
            throws Exception {
    	byte[] encryptedData = Base64Utils.decodeFromString(encrypted);
        byte[] keyBytes = Base64Utils.decodeFromString(privateKey);  
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());  
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);  
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm(), new BouncyCastleProvider());  
        cipher.init(Cipher.DECRYPT_MODE, privateK);  
        int inputLen = encryptedData.length;  
        ByteArrayOutputStream out = new ByteArrayOutputStream();  
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密  
        while (inputLen - offSet > 0) {  
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {  
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);  
            } else {  
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);  
            }  
            out.write(cache, 0, cache.length);  
            i++;  
            offSet = i * MAX_DECRYPT_BLOCK;  
        }
        byte[] decryptedData = out.toByteArray();  
        out.close();  
        return new String(decryptedData);
    }  
  
    /**
     * <p> 
     * 公钥解密 
     * </p> 
     *  
     * @param encrypted 已加密数据 
     * @param publicKey 公钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */  
    public static String decryptByPublicKey(String encrypted, String publicKey)  
            throws Exception {
    	byte[] encryptedData = Base64Utils.decodeFromString(encrypted);
        byte[] keyBytes = Base64Utils.decodeFromString(publicKey);  
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);  
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());  
        Key publicK = keyFactory.generatePublic(x509KeySpec);  
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm(), new BouncyCastleProvider());  
        cipher.init(Cipher.DECRYPT_MODE, publicK);  
        int inputLen = encryptedData.length;  
        ByteArrayOutputStream out = new ByteArrayOutputStream();  
        int offSet = 0;  
        byte[] cache;  
        int i = 0;  
        // 对数据分段解密  
        while (inputLen - offSet > 0) {  
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {  
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);  
            } else {  
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);  
            }  
            out.write(cache, 0, cache.length);  
            i++;  
            offSet = i * MAX_DECRYPT_BLOCK;  
        }
        byte[] decryptedData = out.toByteArray();  
        out.close();  
        return new String(decryptedData);  
    }  
  
    /**
     * <p> 
     * 公钥加密 
     * </p> 
     *  
     * @param source 源数据 
     * @param publicKey 公钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */  
    public static String encryptByPublicKey(String source, String publicKey)  
            throws Exception {
    	byte[] data = source.getBytes();
        byte[] keyBytes = Base64Utils.decodeFromString(publicKey);  
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);  
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());
        Key publicK = keyFactory.generatePublic(x509KeySpec);  
        // 对数据加密  
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm(), new BouncyCastleProvider());  

        cipher.init(Cipher.ENCRYPT_MODE, publicK);  
        int inputLen = data.length;  
        ByteArrayOutputStream out = new ByteArrayOutputStream();  
        int offSet = 0;  
        byte[] cache;  
        int i = 0;  
        // 对数据分段加密  
        while (inputLen - offSet > 0) {  
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {  
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);  
            } else {  
                cache = cipher.doFinal(data, offSet, inputLen - offSet);  
            }  
            out.write(cache, 0, cache.length);  
            i++;  
            offSet = i * MAX_ENCRYPT_BLOCK;  
        } 
        byte[] encryptedData = out.toByteArray();  
        out.close();  
        return Base64Utils.encodeToString(encryptedData);  
    }  
  
    /** 
     * <p> 
     * 私钥加密 
     * </p> 
     *  
     * @param source 源数据 
     * @param privateKey 私钥(BASE64编码) 
     * @return 
     * @throws Exception 
     */  
    public static String encryptByPrivateKey(String source, String privateKey)  
            throws Exception {  
    	byte[] data = source.getBytes();
        byte[] keyBytes = Base64Utils.decodeFromString(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);  
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM, new BouncyCastleProvider());  
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);  
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm(), new BouncyCastleProvider());  
        cipher.init(Cipher.ENCRYPT_MODE, privateK);  
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();  
        int offSet = 0;  
        byte[] cache;  
        int i = 0;  
        // 对数据分段加密  
        while (inputLen - offSet > 0) {  
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {  
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);  
            } else {  
                cache = cipher.doFinal(data, offSet, inputLen - offSet);  
            }  
            out.write(cache, 0, cache.length);  
            i++;  
            offSet = i * MAX_ENCRYPT_BLOCK;  
        }
        byte[] encryptedData = out.toByteArray();  
        out.close();
        return Base64Utils.encodeToString(encryptedData);
    }  
  
    /**
     * <p> 
     * 获取私钥 
     * </p> 
     *  
     * @param keyMap 密钥对 
     * @return 
     * @throws Exception 
     */  
    public static String getPrivateKey(Map<String, Object> keyMap)  
            throws Exception {  
        Key key = (Key) keyMap.get(PRIVATE_KEY);  
        return Base64Utils.encodeToString(key.getEncoded());
    }  
  
    /**
     * <p> 
     * 获取公钥 
     * </p> 
     *  
     * @param keyMap 密钥对 
     * @return 
     * @throws Exception 
     */  
    public static String getPublicKey(Map<String, Object> keyMap)  
            throws Exception {  
        Key key = (Key) keyMap.get(PUBLIC_KEY);  
        return Base64Utils.encodeToString(key.getEncoded());
    }
  
    
    public static void main(String[] args) throws Exception {
//		Map<String, Object> keyMap = genKeyPair();
//		String privateKey = getPrivateKey(keyMap);
//		String publicKey = getPublicKey(keyMap);
//		System.out.println("privateKey=" + privateKey);
//		System.out.println("publicKey=" + publicKey);
//		
//		String md5String = "亚信科技能力开放平台V1.0";
//		md5String = MD5Util.MD5(MD5_String);
//		System.out.println("MD5加密后：" + md5String);
//		
//		String encrypt = RSAUtils.encryptByPrivateKey(md5String, privateKey);
//		System.out.println("RSA加密后：" + encrypt);
//		String decrypt = RSAUtils.decryptByPublicKey(encrypt, publicKey);
//		System.out.println("RSA解密后：" + decrypt);

    	String md5 = "240";
    	String privateKey = "MIIBhQIBADANBgkqhkiG9w0BAQEFAASCAW8wggFrAgEAAkwAlDShtZwwonvlA4xKqBDBgthUfguz1kr/RKCyKGMXr+2TpAli+nyQz6LmiQo+/IpaE7ewcR+SCN8G/qm4w5H/qT5f1oXtJMclP2EfAgMBAAECSwNIAwiNU7pVOeXRNlnwPQiTl5NO2QV2lZ5EXI1uXDjl7q3kE0/t5OhxN8KwqXB8sLmVxbmlNoeTALHdksJTDl9AFbke+jtLONKESQImDeJJbxxZu+Ma9190Y3XoEbDz+EgtmjP3SpgRu1MsO2Sokna4VP0CJgqss1igvW8m7QTqV5xVdJlnjxLOMHZEa0ZmTYHRs4SxXnxKttdLAiYCwlWVnyy2Cgvx3SZkHapg2amiTbXCT1F1oYLkl0LTCs31TWKUgQImBAWVfOry9JIB8zwnzisUR0gRS9CLycN1d4zL3wGXVYNOSh4MTYkCJgjzuL4auxyZVFqcbBAHT/TD8JbCjwwHvhg6265pv3sZ0W/1OQEW";
    	String publicKey = "MGcwDQYJKoZIhvcNAQEBBQADVgAwUwJMAJQ0obWcMKJ75QOMSqgQwYLYVH4Ls9ZK/0SgsihjF6/tk6QJYvp8kM+i5okKPvyKWhO3sHEfkgjfBv6puMOR/6k+X9aF7STHJT9hHwIDAQAB";
    	
    	String e = RSAUtils.encryptByPrivateKey(md5, privateKey);
    	System.out.println(e);
    	
//    	e = "YXaZCEHR7eFNWhuV4NJLsTZTgtqTHMirEeKJtpiUnyNdXJxYszF9HmbRRfs4HZKPw2P6E4a0GUhd8TmQOFUyFCoFSRxBcP7aVCjaZRgEuHmUXDy8CWHwyKzBosA1gnEpgLvjiXeTYz0vsMPg3u8FWD9Hom1sjZONEQtc+dr2dJBcU1Bl4dQRuVAhQpARPn7nciYTaT6H";
    	String d = RSAUtils.decryptByPublicKey(e, publicKey);
    	System.out.println(d);

    	System.out.println(RSAUtils.encryptByPublicKey(md5, publicKey));
    	String sign = "ak4BXVpwaqJ2U2+iigAKLS/KgQYzGlTQuuQuwoJ/fxv9seikdR4j902hAxJxJypJsJGGWWApgBuQvoNI4TNov+QUfmysY86Br/MY";
    	System.out.println(RSAUtils.decryptByPrivateKey(sign, privateKey));
	}
}